from django.db import transaction
from ..models import ScorePrediction, ImprovementRecommendation
from ..ml.features.feature_engineer import FeatureEngineer
from ..ml.predictors.score_predictor import ScorePredictor
from users.models import Student
from score.models import Subject, ExamRecord
from django.core.exceptions import ObjectDoesNotExist


class PredictionService:
    """
    预测服务 - 简单版本
    目标：让预测功能先跑起来，后续再优化
    """

    def __init__(self):
        # 先简单初始化，后续再连接其他模块
        self.predictor = ScorePredictor()
        self.feature_engineer = FeatureEngineer()
        self.data_processor = None
        self.ml_enabled = self.predictor.is_ready()

    def predict_student_score(self, student_id, subject_id, target_exam_date):
        """
        预测学生成绩 - 简单版本
        先用规则-based预测，后续接入机器学习
        """
        try:
            print(f"🔍 开始预测: 学生{student_id}, 科目{subject_id}")

            # 1. 基础数据验证和获取
            student, subject = self._get_basic_data(student_id, subject_id)
            if not student or not subject:
                return {
                    'success': False,
                    'error': '学生或科目不存在'
                }

            # 2. 收集学生历史数据
            student_data = self._collect_student_data(student, subject)

            # 3. 🎯 使用特征工程计算特征
            features = self.feature_engineer.extract_features(student_data)
            print(f"📊 计算出的特征: {features}")

            # 4. 使用简单规则进行预测
            if self.ml_enabled:
                # 尝试ML预测
                ml_result = self.predictor.predict(features)

                if ml_result['success']:
                    prediction_result = self._format_ml_prediction(ml_result, student_data)
                    algorithm_used = 'machine_learning'
                    print(f"✅ 使用ML预测，分数: {ml_result['predicted_score']:.1f}")
                else:
                    # ML失败，回退到规则预测
                    prediction_result = self._simple_rule_based_prediction(student_data, subject)
                    algorithm_used = 'rule_based_fallback'
                    print(f"⚠️ ML预测失败，使用规则预测: {ml_result.get('error')}")
            else:
                # ML未启用，使用规则预测
                prediction_result = self._simple_rule_based_prediction(student_data, subject)
                algorithm_used = 'rule_based'
                print("ℹ️ ML未启用，使用规则预测")

            # 5. 保存预测结果到数据库
            prediction_record = self._save_prediction_record(
                student=student,
                subject=subject,
                target_exam_date=target_exam_date,
                prediction_result=prediction_result,
                student_data=student_data,
                features=features,
                algorithm_used=algorithm_used
            )

            # 6. 生成简单的学习建议
            recommendations = self._generate_simple_recommendations(
                prediction_record,
                prediction_result,
                student_data
            )

            # 7. 返回完整结果
            return {
                'success': True,
                'prediction_id': prediction_record.id,
                'predicted_score': prediction_result['predicted_score'],
                'confidence_interval': prediction_result['confidence_interval'],
                'key_factors': prediction_result['key_factors'],
                'recommendations': recommendations,
                'risk_level': prediction_result['risk_level'],
                'algorithm_used': algorithm_used,
                'ml_enabled': self.ml_enabled,
                'model_confidence': prediction_result.get('model_confidence', 0.8)
            }

        except ObjectDoesNotExist as e:
            return {
                'success': False,
                'error': f'数据不存在: {str(e)}'
            }
        except Exception as e:
            print(f"❌ 预测服务错误: {str(e)}")
            return {
                'success': False,
                'error': f'预测失败: {str(e)}'
            }

    def _format_ml_prediction(self, ml_result, student_data):
        """格式化ML预测结果"""
        predicted_score = ml_result['predicted_score']
        full_score = student_data['subject_full_score']

        # 基于ML置信度计算区间
        confidence_width = (1 - ml_result['confidence']) * 20  # 动态区间
        confidence_lower = max(0, predicted_score - confidence_width)
        confidence_upper = min(full_score, predicted_score + confidence_width)

        return {
            'predicted_score': predicted_score,
            'confidence_interval': [confidence_lower, confidence_upper],
            'key_factors': self._analyze_key_factors(ml_result, student_data),
            'risk_level': self._assess_risk_level(predicted_score, full_score),
            'algorithm_used': 'machine_learning',
            'model_confidence': ml_result['confidence']
        }

    def _get_basic_data(self, student_id, subject_id):
        """获取基础数据"""
        try:
            student = Student.objects.get(id=student_id)
            subject = Subject.objects.get(id=subject_id)
            return student, subject
        except ObjectDoesNotExist:
            return None, None

    def _collect_student_data(self, student, subject):
        """只收集原始数据，不进行任何计算"""
        print(f"📊 收集学生{student.name}的原始数据...")

        # 获取历史考试成绩
        exam_records = ExamRecord.objects.filter(
            student=student,
            subject=subject
        ).order_by('-exam__exam_date')

        # 只返回原始数据，不计算任何统计信息
        return {
            'student': student,
            'subject': subject,
            'exam_records': list(exam_records),
            'historical_scores': [record.score for record in exam_records],  # 原始成绩列表
            'subject_full_score': subject.full_score  # 科目满分
        }

    def _simple_rule_based_prediction(self, student_data, subject):
        """简单规则预测 - 基于历史成绩的规则"""
        print("🧮 使用简单规则进行预测...")

        stats = student_data['statistics']
        full_score = student_data['subject_full_score']

        # 基础预测逻辑
        if stats['exam_count'] == 0:
            # 没有历史成绩：预测为满分的65%
            base_prediction = full_score * 0.65
            confidence_width = full_score * 0.15  # 15%的波动范围
        else:
            # 有历史成绩：基于最近成绩和趋势
            base_prediction = stats['recent_score']

            # 如果有多次考试，考虑趋势
            if stats['exam_count'] >= 2:
                scores = student_data['historical_scores']
                # 简单趋势：最近3次成绩的平均
                recent_scores = scores[:min(3, len(scores))]
                trend = sum(recent_scores) / len(recent_scores)
                # 结合最近成绩和趋势
                base_prediction = (stats['recent_score'] * 0.7 + trend * 0.3)

            # 置信区间宽度基于成绩稳定性
            score_range = stats['max_score'] - stats['min_score']
            confidence_width = max(5, score_range * 0.3)  # 至少5分，最多30%的范围

        # 确保预测分数在合理范围内
        predicted_score = max(0, min(full_score, base_prediction))

        # 计算置信区间
        confidence_lower = max(0, predicted_score - confidence_width)
        confidence_upper = min(full_score, predicted_score + confidence_width)

        # 分析关键因素
        key_factors = self._analyze_key_factors(student_data, predicted_score)

        # 风险评估
        risk_level = self._assess_risk_level(student_data, predicted_score)

        return {
            'predicted_score': round(predicted_score, 1),
            'confidence_interval': [
                round(confidence_lower, 1),
                round(confidence_upper, 1)
            ],
            'key_factors': key_factors,
            'risk_level': risk_level,
            'algorithm_used': 'simple_rule_based'
        }

    def _analyze_key_factors(self, student_data, predicted_score):
        """分析关键影响因素 - 现有逻辑"""
        factors = []
        stats = student_data['statistics']
        full_score = student_data['subject_full_score']

        # 基于历史成绩数量
        if stats['exam_count'] == 0:
            factors.append({
                'type': 'data_insufficient',
                'name': '缺乏历史数据',
                'impact': 3.0,
                'description': '没有历史成绩记录，预测准确性较低'
            })

        # 基于成绩稳定性
        if stats['exam_count'] >= 2:
            score_range = stats['max_score'] - stats['min_score']
            if score_range > full_score * 0.3:
                factors.append({
                    'type': 'score_instability',
                    'name': '成绩波动大',
                    'impact': 2.5,
                    'description': f'成绩波动范围达{score_range:.1f}分，需要提高稳定性'
                })

        # 基于与满分的差距
        if predicted_score < full_score * 0.6:
            factors.append({
                'type': 'low_performance',
                'name': '基础薄弱',
                'impact': 4.0,
                'description': '当前水平较低，需要加强基础知识'
            })

        if not factors:
            factors.append({
                'type': 'normal_performance',
                'name': '正常水平',
                'impact': 1.0,
                'description': '保持当前学习节奏'
            })

        return factors

    def _assess_risk_level(self, student_data, predicted_score):
        """风险评估 - 现有逻辑"""
        stats = student_data['statistics']
        full_score = student_data['subject_full_score']

        risk_score = 0

        # 数据不足风险
        if stats['exam_count'] == 0:
            risk_score += 2

        # 成绩波动风险
        if stats['exam_count'] >= 2:
            score_range = stats['max_score'] - stats['min_score']
            if score_range > full_score * 0.3:
                risk_score += 2
            elif score_range > full_score * 0.2:
                risk_score += 1

        # 低分风险
        if predicted_score < full_score * 0.6:
            risk_score += 2

        # 确定风险等级
        if risk_score >= 4:
            return 'high'
        elif risk_score >= 2:
            return 'medium'
        else:
            return 'low'

    def _save_prediction_record(self, student, subject, target_exam_date,
                              prediction_result, student_data, features, algorithm_used):
        """保存预测记录 - 增强版本"""
        print("💾 保存预测结果到数据库...")

        prediction = ScorePrediction.objects.create(
            student=student,
            subject=subject,
            predicted_score=prediction_result['predicted_score'],
            confidence_interval_lower=prediction_result['confidence_interval'][0],
            confidence_interval_upper=prediction_result['confidence_interval'][1],
            target_exam_date=target_exam_date,
            algorithm_used=algorithm_used,
            model_version='ml_v1.0' if algorithm_used == 'machine_learning' else 'rule_v1.0',
            input_features={
                'statistical_features': features,
                'historical_scores': student_data['historical_scores'],
                'algorithm': algorithm_used
            },
            key_factors=prediction_result['key_factors'],
            training_data_size=student_data['statistics']['exam_count'],
            ml_confidence=prediction_result.get('model_confidence', 0.8)
        )

        print(f"✅ 预测记录已保存，ID: {prediction.id}, 算法: {algorithm_used}")
        return prediction

    def _generate_simple_recommendations(self, prediction_record, prediction_result, student_data):
        """生成简单的学习建议"""
        recommendations = []

        stats = student_data['statistics']
        factors = prediction_result['key_factors']

        # 基于关键因素生成建议
        for factor in factors:
            if factor['type'] == 'data_insufficient':
                recommendations.append({
                    'priority': 1,
                    'type': 'data_collection',
                    'content': '建议先进行几次模拟考试，积累历史数据',
                    'expected_impact': 2.0,
                    'time_required': 10
                })

            elif factor['type'] == 'score_instability':
                recommendations.append({
                    'priority': 2,
                    'type': 'stability_improvement',
                    'content': '重点提高考试稳定性，避免大起大落',
                    'expected_impact': 3.0,
                    'time_required': 15
                })

            elif factor['type'] == 'low_performance':
                recommendations.append({
                    'priority': 1,
                    'type': 'foundation_building',
                    'content': '需要加强基础知识学习，打好基础',
                    'expected_impact': 5.0,
                    'time_required': 20
                })

        # 如果没有特定建议，给出通用建议
        if not recommendations:
            if stats['exam_count'] > 0:
                recommendations.append({
                    'priority': 3,
                    'type': 'maintain_progress',
                    'content': '保持当前学习节奏，定期检测进步情况',
                    'expected_impact': 1.0,
                    'time_required': 5
                })
            else:
                recommendations.append({
                    'priority': 2,
                    'type': 'start_practice',
                    'content': '开始系统学习和模拟练习',
                    'expected_impact': 3.0,
                    'time_required': 10
                })

        # 保存建议到数据库
        for rec_data in recommendations:
            ImprovementRecommendation.objects.create(
                prediction=prediction_record,
                priority=rec_data['priority'],
                recommendation_type=rec_data['type'],
                content=rec_data['content'],
                expected_impact=rec_data['expected_impact'],
                time_required=rec_data['time_required']
            )

        return recommendations


# 创建服务实例，方便直接使用
prediction_service = PredictionService()